using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace MKDS_Course_Editor.GCN.BMD
{
    class INF1
    {
        public class Inf1Header
        {
            public string tag; //'INF1'
            public UInt32 sizeOfSection;
            public UInt16 unknown1;
            public UInt16 pad; //0xffff
            public UInt32 unknown2;
            public UInt32 vertexCount; //number of coords in VTX1 section
            public UInt32 offsetToEntries; //offset relative to Inf1Header start
        }

        //This stores the scene graph of the file
        public class Inf1Entry
        {
            //0x10: Joint
            //0x11: Material
            //0x12: Shape (ie. Batch)
            //0x01: Hierarchy down (insert node), new child
            //0x02: Hierarchy up, close child
            //0x00: Terminator
            public UInt16 type;

            //Index into Joint, Material or Shape table
            //always zero for types 0, 1 and 2
            public UInt16 index;
        }
        public class Node:Inf1Entry //same as Inf1Entry
        {
            //public UInt16 type, index;
        }

        public class Inf1
        {
            public int numVertices; //no idea what's this good for ;-)

            public List<Node> scenegraph = new List<Node>();
        }
        public class SceneGraph
        {
            public int type, index;
            public List<SceneGraph> children = new List<SceneGraph>();
        }
        private static void readInf1Header(EndianBinaryReader er, Inf1Header h)
        {
            h.tag = er.ReadString(Encoding.ASCII, 4);
            h.sizeOfSection = er.ReadUInt32();
            //Helper.toDWORD(h.sizeOfSection);
            h.unknown1 = er.ReadUInt16();
            //Helper.toWORD(h.unknown1);
            h.pad = er.ReadUInt16();
            //Helper.toWORD(h.pad);
            h.unknown2 = er.ReadUInt32();
            //Helper.toDWORD(h.unknown2);
            h.vertexCount = er.ReadUInt32();
            //Helper.toDWORD(h.vertexCount);
            h.offsetToEntries = er.ReadUInt32();
            //Helper.toDWORD(h.offsetToEntries);
        }

        private static void readInf1Entry(EndianBinaryReader er, Inf1Entry e)
        {
            e.type = er.ReadUInt16();
            e.index = er.ReadUInt16();
        }

        public static void dumpInf1(EndianBinaryReader er, Inf1 dst)
        {
            long inf1Offset = er.BaseStream.Position;

            //read header
            Inf1Header h = new Inf1Header();
            readInf1Header(er, h);

            dst.numVertices = (int)h.vertexCount;

            //read scene graph
            er.BaseStream.Position = inf1Offset + h.offsetToEntries;

            Inf1Entry e = new Inf1Entry();
            readInf1Entry(er, e);

            while (e.type != 0)
            {
                Node node = new Node() { type = e.type, index = e.index };
                dst.scenegraph.Add(node);
                e = new Inf1Entry();
                readInf1Entry(er, e);
            }
        }

        //the following is only convenience stuff
        int buildSceneGraph(Inf1 inf1, SceneGraph sg, int j)
        {
            for (int i = j; i < inf1.scenegraph.Count; ++i)
            {
                Node n = inf1.scenegraph[i];

                if (n.type == 1)
                    i += buildSceneGraph(inf1, sg.children.Last(), i + 1);
                else if (n.type == 2)
                    return i - j + 1;
                else if (n.type == 0x10 || n.type == 0x11 || n.type == 0x12)
                {
                    SceneGraph t = new SceneGraph();
                    t.type = n.type; t.index = n.index;
                    sg.children.Add(t);
                }
                else
                {
                    //warn("buildSceneGraph(): unexpected node type %d", n.type);
                }

            }

            //remove dummy node at root
            if (sg.children.Count == 1)
            {
                SceneGraph t = sg.children[0];
                sg = t; //doesn't work without the temporary (msvc bug?)
            }
            else
            {
                sg.type = sg.index = -1;
                //warn("buildSceneGraph(): Unexpected size %d", sg.children.size());
            }

            return 0;
        }

    }
}
